package com.baizhi.cmfz.config;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Slf4j
@Configuration
@Aspect
public class CacheRedisAspect {

    //操作redis的类
    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 环绕增强:在增强中需要对被aop的方法放行，获取方法执行的返回值
     * 如果redis中已经有查询数据的缓存 而环绕增强可以实现放行
     * 环绕增强可以理解为被aop方法在整个增强方法里面需要用到
     * 而前置增强不需要使用被aop方法 只是在运行这个被aop方法之前运行一下额外功能
     */
    @Around("@annotation(com.baizhi.cmfz.annotation.AddCacheAnnotation)")
    public Object addCache(ProceedingJoinPoint joinPoint) throws Throwable {
        /**
         * 1.获取 key 和 hashkey(方法名+形参)
         * key 代表业务类的对象名 保证在删除的时候将这一类的不同查询方法查询出来的数据全部删除
         */
        String key = joinPoint.getTarget().getClass().getName();
        log.debug("获取到的key:{}",key);
        StringBuffer stringBuffer = new StringBuffer();
        //拼接方法名
        stringBuffer.append(joinPoint.getSignature().getName());
        //拼接形参
        Object[] args = joinPoint.getArgs();
        for (Object arg : args) {
            stringBuffer.append(arg);
        }
        String hashKey = stringBuffer.toString();
        log.info("获取到的hashKey：{}",hashKey);

        /**
         * 2利用第一步获取的两个key在redis中查询 看看是否已经有了缓存
         */
        HashOperations hashOperations = redisTemplate.opsForHash();
        Object result = hashOperations.get(key, hashKey);
        if(result==null){
            log.info("redis中没有被aop的方法需要的数据，查询mysql获取数据");
            result = joinPoint.proceed(); //放行操作 可以理解为执行了被aop方法
            Map map = new HashMap();
            map.put(hashKey,result);
            //创建缓存 putAll 将参数map中所有的key-value合并到之前的map中
            hashOperations.putAll(key,map);
            //设置失效时间
            redisTemplate.expire(key,1000, TimeUnit.SECONDS);
        }else {
            log.debug("查询到了redis数据");
        }
        return result;
    }


    /**
     * 删除缓存要保证删除该类型的所有缓存(增删改操作了) 所以选择hash类型存储
     * 因为当你增删改的时候 所有的查询方法之前查询出来并存到缓存的数据 都需要重新弄 所以都需要删掉
     * @param joinPoint
     */
    @Before("@annotation(com.baizhi.cmfz.annotation.DeleteCacheAnnotation)")
    public void deleteCache(JoinPoint joinPoint){
        //获取key
        String key = joinPoint.getTarget().getClass().getName();
        //删除redis中的缓存
        redisTemplate.delete(key);
    }


}
